#include "friend_module.h"

#include "burst_module.h"
#include "login_module.h"
#include "protocol_client.h"
#include "repo.h"
#include "weilapb.h"
#include "weilapb_defines.h"
#include "wlsdk_define.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    wlsdk_message_callback callback;
} wl_friend_global;

static wl_friend_global s_friend_global;

static wl_int32
    friend_protocol_client_request_callback(PBWeilaMsg* message, void* content, wl_uint32 contentlen, void* context);
static wl_int32 friend_protocol_client_listen_callback(PBWeilaMsg* message, void* context);
static void process_sync_friend_infos_message(PBWeilaMsg* message, void* content, wl_uint32 contentlen, void* context);
static wl_int32 friend_message_callback(wl_int32 msgid, void* data, wl_uint32 datalen);
static void     process_friend_changed_message(PBWeilaMsg* message, void* context);

static void friend_sdk_message_callback(wl_uint32 msgid, wl_int32 resultcode, void* msgdata, wl_uint32 datalen) {
    if (s_friend_global.callback) {
        s_friend_global.callback(msgid, resultcode, msgdata, datalen);
    }
}

wl_int32 friend_module_init(wlsdk_message_callback callback) {
    wl_int32  ret = 0;
    wl_module module;

    WLLOGI("friend_module_init");
    memset(&module, 0, sizeof(wl_module));
    module.moduleid = WL_MODULE_FRIEND;
    module.taskid   = WL_TASK_APP;
    module.callback = friend_message_callback;
    ret             = wl_core_register_module(&module);
    if (0 != ret) {
        WLLOGW("wl_core_register_module friend fail");
        return ret;
    }
    s_friend_global.callback = callback;

    protocol_client_add_listen(
        WL_FRIEND_NEW_FRIEND_MSG, WEILA_MSG_IND, friend_protocol_client_listen_callback, wl_null);
    protocol_client_add_listen(
        WL_FRIEND_DELETE_FRIEND_MSG, WEILA_MSG_IND, friend_protocol_client_listen_callback, wl_null);
    return ret;
}

wl_int32 friend_module_end(void) {
    WLLOGI("friend_module_end");
    wl_core_unregister_module(WL_MODULE_FRIEND);
    s_friend_global.callback = wl_null;
    return 0;
}

static void process_get_friends(void* data, wl_int32 datalen) {
    wl_list* friend_list = repo_get_friend_list();
    wl_int32 count       = wl_list_size(friend_list);

    if (count > 0) {
        wl_uint32          friends_size = sizeof(wlsdk_friend_list) + sizeof(wlsdk_friend) * count;
        wlsdk_friend_list* friends      = (wlsdk_friend_list*)wl_malloc(friends_size);
        wl_uint32          pos          = 0;
        if (friends) {
            wl_uint32 friend_count = 0;
            for (pos = 0; pos < count; pos++) {
                repo_friend* friend = (repo_friend*)wl_list_get(friend_list, pos);
                // 好友与部门成员
                if ((friend->type == 0) || (friend->type == 1)) {
                    memcpy(&friends->friends[friend_count], &friend->friend, sizeof(wlsdk_friend));
                    friend_count++;
                }
            }
            friends->count = friend_count;
            friend_sdk_message_callback(WLSDK_MSG_FRIEND_GET_FRIENDS, WLSDK_RESULT_SUCCESS, friends, friends_size);
            wl_free(friends);
            return;
        }
    }
    friend_sdk_message_callback(WLSDK_MSG_FRIEND_GET_FRIENDS, WLSDK_RESULT_SUCCESS, wl_null, 0);
}

static void process_sync_friend_info(void* data, wl_int32 datalen) {
    PBEncResult enc_result = weilapb_buildEmbeddedGetFriendInfo(repo_get_friend_updated(), wl_null, 0, REPO_FRIEND_MAX);
    wl_int32    resultcode = protocol_client_send_request(
        &enc_result, wl_null, 0, PROTOCOL_CLIENT_REQUEST_TIMEOUT_60, friend_protocol_client_request_callback, wl_null);
    if (0 > resultcode) {
        protocol_client_disconnect();
        WLLOGW("protocol_client_send_request error");
    }
}

static wl_int32 friend_message_callback(wl_int32 msgid, void* data, wl_uint32 datalen) {
    WLLOGD("msgid %d", msgid);
    switch (msgid) {
        case FRIEND_MSG_GET_FRIENDS:
            process_get_friends(data, datalen);
            break;
        case FRIEND_MSG_SYNC_FRIEND_INFO:
            process_sync_friend_info(data, datalen);
            break;
        default:
            WLLOGW("msgid %d not support", msgid);
            break;
    }
    return 0;
}

static wl_int32
    friend_protocol_client_request_callback(PBWeilaMsg* message, void* content, wl_uint32 contentlen, void* context) {
    WLLOGD("message %d resultCode %d", message->message, message->resultCode);
    switch (message->message) {
        case WL_FRIEND_GET_EMBEDDED_FRIEND_INFOS:
            process_sync_friend_infos_message(message, content, contentlen, context);
            break;
        default:
            break;
    }
    return 0;
}

static wl_int32 friend_protocol_client_listen_callback(PBWeilaMsg* message, void* context) {
    WLLOGD("message %d", message->message);
    switch (message->message) {
        case WL_FRIEND_NEW_FRIEND_MSG:
        case WL_FRIEND_DELETE_FRIEND_MSG:
            process_friend_changed_message(message, context);
            break;
        default:
            break;
    }
    return 0;
}

void process_sync_friend_infos_message(PBWeilaMsg* message, void* content, wl_uint32 contentlen, void* context) {
    if (WLSDK_RESULT_SUCCESS == message->resultCode) {
        PBGetEmbeddedFriendInfoRsp* response = (PBGetEmbeddedFriendInfoRsp*)message->pContent;
        WLLOGI("latest updated %d count %d", response->latestUpdated, response->friendInfoList.listCount);
        if (response->friendInfoList.listCount) {
            repo_friend* friendinfos =
                (repo_friend*)wl_malloc(sizeof(repo_friend) * response->friendInfoList.listCount);
            wl_uint32   friendinfos_index = 0;
            PBLinkItem* item              = wl_null;
            if (wl_null == friendinfos) {
                WLLOGW("malloc fail");
                return;
            }
            item = response->friendInfoList.pLinks;
            while (item) {
                PBFriendEmbeddedInfo* friendinfo = (PBFriendEmbeddedInfo*)item->data;
                if (0 == friendinfo->status) {
                    friendinfos[friendinfos_index].friend.userid = friendinfo->userId;
                    strncpy(friendinfos[friendinfos_index].friend.number,
                            friendinfo->number,
                            sizeof(friendinfos[friendinfos_index].friend.number));
                    friendinfos[friendinfos_index]
                        .friend.number[sizeof(friendinfos[friendinfos_index].friend.number) - 1] = '\0';
                    strncpy(friendinfos[friendinfos_index].friend.nick,
                            friendinfo->nick,
                            sizeof(friendinfos[friendinfos_index].friend.nick));
                    friendinfos[friendinfos_index].friend.nick[sizeof(friendinfos[friendinfos_index].friend.nick) - 1] =
                        '\0';
                    friendinfos[friendinfos_index].friend.shieldstatus  = friendinfo->recvStatus;
                    friendinfos[friendinfos_index].friend.tts           = friendinfo->tts;
                    friendinfos[friendinfos_index].friend.locationshare = friendinfo->locationShared;
                    friendinfos[friendinfos_index].type                 = REPO_FRIEND_SINGLE;
                    WLLOGD("user id %d number %s nick %s shieldstatus %d tts %d locationshare %d",
                           friendinfos[friendinfos_index].friend.userid,
                           friendinfos[friendinfos_index].friend.number,
                           friendinfos[friendinfos_index].friend.nick,
                           friendinfos[friendinfos_index].friend.shieldstatus,
                           friendinfos[friendinfos_index].friend.tts,
                           friendinfos[friendinfos_index].friend.locationshare);
                    friendinfos_index++;
                }
                item = item->pNext;
            }
            repo_set_friends(response->latestUpdated, friendinfos, friendinfos_index);
            wl_core_send_message(WL_MODULE_BURST, BURST_MSG_CHECK_SESSION, wl_null, 0);
            wl_free(friendinfos);
        } else {
            repo_set_friends(response->latestUpdated, wl_null, 0);
        }
        protocol_client_set_session_depend(PROTOCOL_CLIENT_SESSION_DEPEND_FRIEND);
        friend_sdk_message_callback(WLSDK_MSG_FRIEND_CHANGED, WLSDK_RESULT_SUCCESS, wl_null, 0);
        WLLOGW("finished");
    } else {
        wl_core_send_message(WL_MODULE_LOGIN, LOGIN_MSG_CLOSE_PROTOCOL_CLIENT, wl_null, 0);
        WLLOGW("result %d", message->resultCode);
    }
}

void process_friend_changed_message(PBWeilaMsg* message, void* context) {
    // 同步好友
    wl_core_send_message(WL_MODULE_FRIEND, FRIEND_MSG_SYNC_FRIEND_INFO, wl_null, 0);
}

#ifdef __cplusplus
}
#endif
